package com.zhixing.user.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zhixing.common.domain.entity.UserInfo;
import com.zhixing.common.domain.enums.Role;
import com.zhixing.common.exception.*;
import com.zhixing.common.utils.JwtUtil;
import com.zhixing.user.domain.dto.LoginDTO;
import com.zhixing.user.domain.dto.PasswordDTO;
import com.zhixing.user.domain.dto.RegisterDTO;
import com.zhixing.user.domain.dto.UserDTO;
import com.zhixing.user.domain.entity.User;
import com.zhixing.user.domain.enums.UserStatus;
import com.zhixing.user.domain.vo.TokenVO;
import com.zhixing.user.domain.vo.UserInfoVO;
import com.zhixing.user.domain.vo.UserVO;
import com.zhixing.user.mapper.UserMapper;
import com.zhixing.user.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
import static com.zhixing.common.constant.Constant.*;
import static com.zhixing.common.domain.enums.HttpStatus.*;

@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {

    private final UserMapper userMapper;
    private final StringRedisTemplate stringRedisTemplate;
    private final RedisTemplate<String, Object> redisTemplate;
    private final KafkaTemplate<String, Object> kafkaTemplate;

    @Override
    public TokenVO login(LoginDTO loginDTO) {
        // 查找用户
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>()
                .eq(User::getPhone, loginDTO.getPhone())
                .eq(User::getRole, loginDTO.getRole());
        User user = userMapper.selectOne(lqw);
        if (ObjectUtil.isEmpty(user)) throw new ZhixingException(PHONE_OR_PASSWORD_ERROR);

        // 校验密码和用户状态
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        if (!encoder.matches(loginDTO.getPassword(), user.getPassword())) throw new ZhixingException(PHONE_OR_PASSWORD_ERROR);
        if (user.getUserStatus() == UserStatus.ABNORMAL) throw new ZhixingException(USER_STATUS_ABNORMAL);

        // 创建token
        String token = JwtUtil.createToken(new UserInfo(user.getId(), user.getRole()));
        stringRedisTemplate.opsForValue().set(ZHIXING_USER_TOKEN + user.getId(), token, WEEK, TimeUnit.DAYS);
        return new TokenVO(token);
    }

    @Override
    public void register(RegisterDTO registerDTO) {
        // 判断手机号是否已经注册
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>()
                .eq(User::getPhone, registerDTO.getPhone())
                .eq(User::getRole, registerDTO.getRole());
        User user = userMapper.selectOne(lqw);
        if (ObjectUtil.isNotEmpty(user)) throw new ZhixingException(PHONE_ALREADY_REGISTER);

        // 注册用户
        user = new User();
        BeanUtil.copyProperties(registerDTO, user);
        user.setPassword(new BCryptPasswordEncoder().encode(user.getPassword()));
        String prefix = user.getRole() == Role.PASSENGER ? NICKNAME_PREFIX_PASSENGER : NICKNAME_PREFIX_DRIVER;
        user.setNickname(prefix + IdUtil.fastUUID().substring(0, 6));
        userMapper.insert(user);

        // 用户注册事件，初始化钱包，乘客发放新人优惠券，司机开启新人激励
        kafkaTemplate.send(ZHIXING_USER_REGISTER, new UserInfo(user.getId(), user.getRole()));
    }

    @Override
    public void logout(Integer userId) {
        stringRedisTemplate.delete(ZHIXING_USER_TOKEN + userId);
    }

    @Override
    public UserInfoVO getUserInfo(Integer userId) {
        return userMapper.getUserInfo(userId);
    }

    @Override
    public UserVO getDetailInfo(Integer userId) {
        // 查询缓存
        UserVO userVO = (UserVO) redisTemplate.opsForValue().get(ZHIXING_USER_INFO + userId);
        if (ObjectUtil.isNotEmpty(userVO)) return userVO;

        // 查询数据库
        User user = userMapper.selectById(userId);
        userVO = BeanUtil.copyProperties(user, UserVO.class);
        redisTemplate.opsForValue().set(ZHIXING_USER_INFO + userId, userVO, ONE_HOURS, TimeUnit.HOURS);
        return userVO;
    }

    @Override
    public void updateUserInfo(UserDTO userDTO) {
        User user = BeanUtil.copyProperties(userDTO, User.class);
        userMapper.updateById(user);
        redisTemplate.delete(ZHIXING_USER_INFO + user.getId());
    }

    @Override
    public void updatePassword(Integer userId, PasswordDTO passwordDTO) {
        // 校验原密码
        User user = userMapper.selectById(userId);
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        if (!encoder.matches(passwordDTO.getOldPassword(), user.getPassword())) throw new ZhixingException(OLDPASSWORD_ERROR);

        // 修改密码
        user.setPassword(encoder.encode(passwordDTO.getNewPassword()));
        userMapper.updateById(user);
    }
}
